package com.aos.iot.protocol.hll.decode;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import com.aos.iot.socket.common.log.service.MessageLogService;
import com.aos.iot.socket.common.message.Message;
import com.aos.iot.socket.common.protocol.IProtocol;
import com.aos.iot.protocol.hll.util.CodeUtil;
import com.aos.iot.protocol.hll.message.HllMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class HllDecoder extends MessageToMessageDecoder<Object> {

    private final static String HEAD = "55aa";

    private final StringBuffer cache = new StringBuffer();

    private final IProtocol<HllMessage> protocol;

    private final MessageLogService messageLogService;

    public HllDecoder(IProtocol<HllMessage> protocol, MessageLogService messageLogService) {
        this.protocol = protocol;
        this.messageLogService = messageLogService;
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, Object inObject, List<Object> inObjects) throws Exception {
        DatagramPacket datagramPacket = inObject instanceof DatagramPacket ? ((DatagramPacket) inObject) : null;
        ByteBuf in = datagramPacket != null ? datagramPacket.content() : (ByteBuf) inObject;
        int length = in.readableBytes();
        if (length <= 0) {
            return;
        }
        byte[] bytes = new byte[length];
        in.readBytes(bytes);
        //缓冲消息
        cache.append(HexUtil.encodeHexStr(bytes, true));
        //分割解析消息
        AtomicInteger execNum = new AtomicInteger(0);
        while (cache.length() > 0 && execNum.get() < 1) {
            splitDecorator(cache, channelHandlerContext.channel(), datagramPacket, inObjects, execNum);
        }
    }

    private void splitDecorator(StringBuffer payload, Channel channel, DatagramPacket datagramPacket, List<Object> inObjects, AtomicInteger execNum) {
        int length = StrUtil.length(payload);
        if(length > 0) {
            //消息开始位置
            int start = payload.indexOf(HEAD);
            if(start > 0) {
                payload.delete(0, start);
                start = 0;
            }
            if (start > -1) {
                //数据长度开始位置
                int dataLengthStart = start + (4 * 2);
                //数据结束位置
                int dataLengthEnd = dataLengthStart + (2 * 2);
                if (payload.length() > dataLengthEnd) {
                    //数据长度16进制字符串并进行高低位转换
                    String dataLengthHex = CodeUtil.highRotation(StrUtil.sub(payload, dataLengthStart, dataLengthEnd));
                    //数据长度
                    int dataLength = HexUtil.hexToInt(dataLengthHex);
                    //消息总长度
                    int msgLength = dataLength * 2 + 12;
                    if (payload.length() >= msgLength) {
                        String message = StrUtil.sub(payload, start, msgLength);
                        Message inMessageObject = protocol.getParser().boxing(Message.Direction.UP, message);
                        if(inMessageObject != null) {
                            inMessageObject.setSender(datagramPacket != null ? datagramPacket.sender() : channel.remoteAddress());
                            inObjects.add(inMessageObject);
                            ThreadUtil.execute(() -> messageLogService.insertIotLogger(inMessageObject));
                        }
                        payload.delete(start, msgLength);
                        splitDecorator(payload, channel, datagramPacket, inObjects, execNum);
                    } else {
                        execNum.addAndGet(1);
                    }
                } else {
                    execNum.addAndGet(1);
                }
            }  else {
                execNum.addAndGet(1);
            }
        }
    }

}
